package com.gitee.kenewstar.utils.excel;

import com.gitee.kenewstar.exception.CommonException;
import com.gitee.kenewstar.common.annotation.ExcelColumn;
import com.gitee.kenewstar.common.annotation.ExcelSheet;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import java.io.*;
import java.lang.reflect.Field;
import java.util.*;

/**
 * 获取sheet页数量
 * int sheetCount = sheets.getNumberOfSheets();
 * <p>
 *     数据导入工具
 * </p>
 * @author kenewstar
 * @date 2021/7/9
 */
public abstract class DataImportUtil {



	/**
	 * <p>
	 *     获取excel文件中的第一个sheet页数据
	 * </p>
	 * @param is 文件的输入流
	 * @param importClass 导入数据对应的对象类型
	 * @param <T> 范型 t
	 * @return list
	 */
	public static <T> List<T> getSheetData(InputStream is, Class<T> importClass) {
		List<T> sheetData;
		try {
			String sheetName = "";
			ExcelSheet excelSheet = importClass.getAnnotation(ExcelSheet.class);
			if (Objects.nonNull(excelSheet)) {
				sheetName = Objects.equals(sheetName, excelSheet.value())
						? importClass.getSimpleName() : excelSheet.value();
			}
			Workbook workbook = WorkbookFactory.create(is);
			Sheet sheet = workbook.getSheet(sheetName);
			int rowNum = sheet.getLastRowNum();
			sheetData = new ArrayList<>(rowNum);
			// 构建标题行信息
			// 列索引  ---  列名
			Map<Short, String> titleMap = buildTitleMap(sheet);
			// 解析导入类的注解
			// 列名   ---  属性名
			Map<String, String> fieldMap = resolveImportClassAnnotation(importClass);

			for (int i = 1; i <= rowNum; i ++) {
				sheetData.add(buildRowObject(importClass, sheet.getRow(i), titleMap, fieldMap));
			}
		} catch (Exception e) {
			throw new CommonException(e);
		}
		return sheetData;
	}

	private static <T> Map<String, String> resolveImportClassAnnotation(Class<T> importClass) {
		// 获取全部属性
		Field[] fields = importClass.getDeclaredFields();
		Map<String, String> fieldMap = new HashMap<>(fields.length);

		for (Field field : fields) {
			ExcelColumn excelColumn = field.getAnnotation(ExcelColumn.class);
			// 属性上注解不为空
			if (Objects.nonNull(excelColumn)) {
				// 列名
				String columnName = excelColumn.value();
				String column = Objects.equals(columnName, "") ? field.getName() : columnName;
				fieldMap.put(column, field.getName());
			}
		}
		return fieldMap;
	}


	/**
	 * <p>
	 *     根据数据行构建数据对象
	 * </p>
	 * @param clazz 数据类型
	 * @param row excel数据行
	 * @param titleMap 标题行数据
	 * @param <T> 范型t
	 * @return 行数据封装后的对象
	 * @throws Exception exception
	 */
	private static <T> T buildRowObject(Class<T> clazz, Row row, Map<Short, String> titleMap, Map<String, String> fieldMap) throws Exception {
		T t = clazz.getConstructor().newInstance();
		// 列数量
		short cellNum = row.getLastCellNum();
		for (short i = 0; i < cellNum; i ++) {
			String fieldName = fieldMap.get(titleMap.get(i));
			if (Objects.nonNull(fieldName)) {
				Field field = clazz.getDeclaredField(fieldName);
				field.setAccessible(true);
				field.set(t, TypeConverter.dataTypeConvert(field, row.getCell(i)));
			}
		}
		return t;
	}

	/**
	 * <p>
	 *     构建标题行的信息对象
	 * </p>
	 * @param sheet sheet对象
	 * @return Map标题信息
	 */
	private static Map<Short, String> buildTitleMap(Sheet sheet) {
		Row titleRow = sheet.getRow(0);
		short cellNum = titleRow.getLastCellNum();
		Map<Short, String> titleMap = new HashMap<>(cellNum);

		for (short i = 0; i < cellNum; i++) {
			// index  --->  cell name
			titleMap.put(i, titleRow.getCell(i).toString());
		}
		return titleMap;
	}

}
